<?php
namespace payment;

class Qqpay
{
    public $apiurl  = '';
    public $key     = '';
    private $config = [
        'appid'            => '',
        'mch_id'           => '',
        'nonce_str'        => '',
        'sign'             => '',
        'body'             => '',
        'attach'           => '',
        'out_trade_no'     => '',
        'fee_type'         => 'CNY',
        'total_fee'        => '',
        'spbill_create_ip' => '0.0.0.0',
        'time_start'       => '',
        'time_expire'      => '',
        'limit_pay'        => '',
        'contract_code'    => '',
        'promotion_tag'    => '',
        'trade_type'       => 'NATIVE',
        'notify_url'       => '',
        'device_info'      => '',

        //查询订单
        'transaction_id'   => '',

        //退款参数
        'out_refund_no'    => '',
        'refund_fee'       => '',
        'op_user_id'       => '',
        'op_user_passwd'   => '',
        'refund_account'   => '',

        //退款查询
        'refund_id'        => '',
    ];

    public function __construct()
    {
        global $_G;
        $this->config['mch_id']    = $_G['setting']['qqpay_mch_id'];
        $this->config['nonce_str'] = random(32);
        $this->key                 = $_G['setting']['qqpay_key'];
    }

    private function curlPost()
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $this->apiurl);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $this->array_to_xml());
        $reponse  = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        $result = \simplexml_load_string($reponse, 'SimpleXMLElement', LIBXML_NOCDATA);
        return json_decode(json_encode($result), true) ?: [];
    }

    private function array_to_xml()
    {
        $this->config['sign'] = $this->sign(array_filter($this->config));
        $param                = array_filter($this->config);
        ksort($param);
        $str = '<xml>' . PHP_EOL;
        foreach ($param as $k => $v) {
            $str .= '<' . $k . '>';
            if (is_array($v)) {
                $str .= '<![CDATA[';
                $str .= json_encode($v, JSON_UNESCAPED_UNICODE);
                $str .= ']]>';
            } else {
                $str .= $v;
            }
            $str .= '</' . $k . '>';
            $str .= PHP_EOL;
        }
        $str .= '</xml>';
        return $str;
    }

    private function sign($param = [])
    {
        ksort($param);
        $str = '';
        foreach ($param as $k => $v) {
            $str .= ($str ? '&' : '') . $k . '=' . $v;
        }
        return strtoupper(md5($str . '&key=' . $this->key));
    }

    public function verify($data, $sign)
    {
        unset($data['sign']);
        if ($this->sign($data) === $sign) {
            return true;
        }
        return false;
    }

    public function setConfig($config)
    {
        $this->config = array_merge($this->config, $config);
        return $this;
    }

    public function setOrder($param)
    {
        foreach ($param as $k => $v) {
            switch ($k) {
                case 'order_id':
                    $this->config['out_trade_no'] = $v;
                    break;
                case 'price':
                    $this->config['total_fee'] = $v * 100;
                    break;
                case 'subject':
                    $this->config['body'] = $v;
                    break;
                case 'body':
                    $this->config['attach'] = $v;
                    break;
                case 'create_ip':
                    $this->config['spbill_create_ip'] = $v != '::1' ? $v : '0.0.0.0';
                    break;
                case 'refund_price':
                    $this->config['refund_fee'] = $v;
                    break;
                case 'refund_order_id':
                    $this->config['out_refund_no'] = $v;
                    break;

                default:
                    if (isset($this->config[$k])) {
                        $this->config[$k] = $v;
                    }
                    break;
            }
        }
        return $this;
    }

    public function unifiedOrder()
    {
        $this->apiurl = 'https://qpay.qq.com/cgi-bin/pay/qpay_unified_order.cgi';
        return $this->curlPost();
    }

    public function queryOrder()
    {
        $this->apiurl = 'https://qpay.qq.com/cgi-bin/pay/qpay_order_query.cgi';
        return $this->curlPost();
    }

    public function closeOrder()
    {
        $this->apiurl = 'https://qpay.qq.com/cgi-bin/pay/qpay_close_order.cgi';
        return $this->curlPost();
    }

    public function refundOrder()
    {
        $this->apiurl = 'https://api.qpay.qq.com/cgi-bin/pay/qpay_refund.cgi';
        return $this->curlPost();
    }

    public function queryRefundOrder()
    {
        $this->apiurl = 'https://qpay.qq.com/cgi-bin/pay/qpay_refund_query.cgi';
        return $this->curlPost();
    }
}
